package com.fy.fyspace.common.auth.aop;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpInterface;
import com.fy.fyspace.common.auth.StpKit;
import com.fy.fyspace.common.auth.annotation.SpaceAuth;
import com.fy.fyspace.common.auth.authenum.SpaceUserPermissionEnum;
import com.fy.fyspace.common.auth.authenum.SpaceUserRoleEnum;
import com.fy.fyspace.constant.ResultMessageConstant;
import com.fy.fyspace.ex.ConditionException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 空间权限校验切面
 */
@Aspect
@Component
@Slf4j
public class SpaceAuthAspect {

    @Resource
    private StpInterface stpInterface;

    @Around("@annotation(com.fy.fyspace.common.auth.annotation.SpaceAuth)")
    public Object checkAuth(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            // 获取方法签名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();

            // 获取注解
            SpaceAuth spaceAuth = method.getAnnotation(SpaceAuth.class);

            // 获取当前登录用户ID
            Object loginId = StpKit.SPACE.getLoginId();

            // 获取用户的权限和角色列表
            List<String> permissionList = stpInterface.getPermissionList(loginId, StpKit.SPACE.loginType);
            List<String> roleList = stpInterface.getRoleList(loginId, StpKit.SPACE.loginType);

            log.debug("用户 {} 的权限id列表: {}", loginId, permissionList);
            log.debug("用户 {} 的角色优先级列表: {}", loginId, roleList);

            // 判断是角色校验还是权限校验
            SpaceUserRoleEnum requiredRole = spaceAuth.role();
            log.info("注解传递的角色待校验参数:{}", requiredRole);
            SpaceUserPermissionEnum[] requiredPermissions = spaceAuth.permissions();

            List<Long> permissionIds = new ArrayList<>();
            for (SpaceUserPermissionEnum requiredPermission : requiredPermissions) {
                permissionIds.add(requiredPermission.getPermissionId());
            }
            log.info("注解传递的权限待校验参数:{}", permissionIds);

            boolean hasPermission;
            if (requiredRole != SpaceUserRoleEnum.SPACE_VISITOR && requiredPermissions.length > 0) {
                log.warn("不能同时校验角色和权限");
                throw new ConditionException(ResultMessageConstant.SYSTEM_ERROR);
            } else if (requiredRole != SpaceUserRoleEnum.SPACE_VISITOR) {
                // 角色校验
                hasPermission = checkRole(requiredRole, roleList);
            } else if (requiredPermissions.length > 0) {
                // 权限校验
                hasPermission = checkAllPermissions(requiredPermissions, permissionList);
            } else {
                // 默认访客权限，直接通过
                hasPermission = true;
            }

            // 如果权限校验失败，抛出异常
            if (!hasPermission) {
                if (requiredRole != SpaceUserRoleEnum.SPACE_VISITOR) {
                    // 角色校验失败
                    Long userRolePriority = roleList.isEmpty() ? 0L : Long.valueOf(roleList.get(0));
                    log.warn("用户 {} 角色优先级不足，当前角色优先级: {}，需要角色优先级: {}",
                            loginId, userRolePriority, requiredRole.getPriority());
                } else if (requiredPermissions.length > 0) {
                    // 权限校验失败，获取用户已有的权限和缺失的权限
                    List<Long> requiredPermissionIds = Arrays.stream(requiredPermissions)
                            .map(SpaceUserPermissionEnum::getPermissionId)
                            .collect(Collectors.toList());

                    List<Long> userPermissionIds = permissionList.stream()
                            .map(Long::valueOf)
                            .collect(Collectors.toList());

                    log.info("用户请求的所有权限:{}", requiredPermissionIds);
                    // 获取用户已有的权限
                    List<Long> hasPermissions = userPermissionIds; // 用户实际拥有的所有权限
                    List<Long> lackPermissions = requiredPermissionIds.stream()
                            .filter(id -> !userPermissionIds.contains(id))
                            .collect(Collectors.toList());

                    log.warn("用户 {} 权限校验失败，已有权限id: {}，缺失权限id: {}",
                            loginId, hasPermissions, lackPermissions);
                }
                throw new ConditionException(ResultMessageConstant.NO_AUTH_ERROR);
            }

            // 权限校验通过，执行原方法
            return joinPoint.proceed();

        } catch (NotLoginException e) {
            // 直接抛出NotLoginException，不包装
            throw e;
        } catch (ConditionException e) {
            throw e;
        } catch (Exception e) {
            log.error("权限校验过程中发生异常", e);
            throw new ConditionException(ResultMessageConstant.SYSTEM_ERROR);
        }
    }

    /**
     * 检查是否满足所有权限要求
     */
    private boolean checkAllPermissions(SpaceUserPermissionEnum[] requiredPermissions, List<String> permissionList) {
        log.debug("用户实际拥有的权限ID列表: {}", permissionList);
        log.debug("需要校验的权限: {}", Arrays.toString(requiredPermissions));

        // 将用户的权限ID转换为Long类型
        List<Long> userPermissionIds = permissionList.stream()
                .map(Long::valueOf)
                .collect(Collectors.toList());

        // 检查每个必需的权限
        for (SpaceUserPermissionEnum requiredPermission : requiredPermissions) {
            Long requiredPermissionId = requiredPermission.getPermissionId();
            if (!userPermissionIds.contains(requiredPermissionId)) {
                log.warn("权限校验失败 - 缺少权限ID: {}", requiredPermissionId);
                return false;
            }
        }

        log.debug("权限校验通过");
        return true;
    }

    /**
     * 检查是否具有指定角色
     */
    private boolean checkRole(SpaceUserRoleEnum requiredRole, List<String> roleList) {
        if (roleList == null || roleList.isEmpty()) {
            log.warn("用户没有任何角色");
            return false;
        }

        try {
            // 获取用户的角色优先级（从redis中获取的是角色优先级）
            Long userRolePriority = Long.valueOf(roleList.get(0));
            // 获取要求的角色优先级
            Long requiredPriority = requiredRole.getPriority();

            log.debug("用户角色优先级: {}, 要求的角色优先级: {}", userRolePriority, requiredPriority);
            // 如果用户的角色优先级大于等于要求的优先级，则允许访问
            return userRolePriority >= requiredPriority;
        } catch (NumberFormatException e) {
            log.error("角色优先级转换失败", e);
            return false;
        }
    }
}